from random import *
from django.contrib.auth.mixins import LoginRequiredMixin
from PIL.Image import logger
from django.contrib.auth import *
from django.http import *
from django.http import request
from django.shortcuts import *
from django.views import *
# Create your views here.
from django_redis import *
from libs.yuntongxun.sms import  CCP
from utils.response_code import RETCODE
from users.models import *
from home.models import *
# from home.models import ArticleCategory, Article
import json

#导入图片验证码
from libs.captcha.captcha import captcha

#注册
from utils.response_code import RETCODE

#注册视图
class RegisterView(View):
    def get(self,request):
        return render(request,'register.html')

    def post(self,request):
        mobile=request.POST.get('mobile')
        password=request.POST.get('password')
        password2=request.POST.get('password2')
        sms_code = request.POST.get('sms_code')

        if not all([mobile,password,password2,sms_code]):
            return HttpResponseBadRequest('参数不全')

        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return HttpResponseBadRequest('手机号码格式不正确')
            # 2-3、密码是否符合格式
        if not re.match(r'^[0-9a-zA-Z]{8,20}$', password) or not re.match(r'^[0-9a-zA-Z]{8,20}$', password2):
            return HttpResponseBadRequest('密码长度、格式不正确。长度8-20，必须是数字、字母')
            # 2-4、密码和确认密码是否一致
        if password != password2:
            return HttpResponseBadRequest('两次输入的密码不一致')
        redis_conn=get_redis_connection()
        redis_sms_code=redis_conn.get('sms:%s' % mobile)
        if redis_sms_code.decode()!=sms_code:
            return HttpResponseBadRequest('短信验证码错误')
        assert isinstance(User.objects.create_user, object)
        user=User.objects.create_user(username=mobile,mobile=mobile,password=password)


        login(request,user)
        resp =redirect(reverse('home:index'))
        resp.set_cookie('is_login',True)
        resp.set_cookie('login_name',user.username)
        return resp


#图片验证码
class ImageView(View):
    def get(self, request):
            '''
                  步骤：
                  1、接收前端传递过来的uuid
                  2、判断uuid失分获取到
                  3、通过调用captcha来生成图片验证码（返回：图片内容和图片二进制）
                  4、将图片内容保存到redis中。uuid作为key，图片内容作为值，同时还需要设置一个过期时间
                  5、返回图片给前端
                  :param request:
                  :return:
             '''
            uuid = request.GET.get('uuid')
            if uuid is None:
                return HttpResponse('没有获取到uuid')
            txt,image=captcha.generate_captcha()
            redis_conn = get_redis_connection('default')
            redis_conn.setex(name='img:%s' % uuid, time=300, value=txt)
            return HttpResponse(image,content_type='image/jpeg')


#接收手机验证码
class SmsCodeView(View):
    def get(self,request):
        mobile=request.GET.get('mobile')
        image_code = request.GET.get('image_code')
        uuid = request.GET.get('uuid')
        if not all([mobile,image_code,uuid]):
            return JsonResponse({"code":RETCODE.NECESSARYPARAMERR,"errmsg":'参数不全'})

        redis_conn =  get_redis_connection()
        #从redis中获取已经存入的图片验证码信息
        image_code_redis= redis_conn.get('img:%s' % uuid)

        if image_code_redis is None:
            return JsonResponse({"code":RETCODE.IMAGECODEERR,"errmsg":'图片按验证码不存在'})
        redis_conn.delete('img:%s' % uuid)
        #
        if image_code.lower() != image_code_redis.decode().lower():
            return JsonResponse({"code":RETCODE.IMAGECODEERR,"errmsg":'图片验证码错误'})

        # 3、生成短信验证码：生成6位数验证码
        sms_code = '%06d' % randint(0, 999999)
        ccp=CCP()
        ccp.send_template_sms('17829041629', [sms_code, 5], 1)
        print(f'你的验证码是:{sms_code}')
        redis_conn.setex('sms:%s' % mobile, 60, sms_code)
        return JsonResponse({"code":RETCODE.OK,"errmsg":'短信发送成功'})


#登录视图
class LoginView(View):
    def get(self,req):
        return render(req,'login.html')

    def post(self,req):
        '''
                实现思路：
                1、接收提交参数
                2、验证参数
                 2-1、手机号码是否符合规则
                 2-2、密码是否符合规则
                3、用户认证登录
                4、状态保持
                5、根据用户选择的是否记住登录状态进行判断
                6、设置cookie信息，为首页显示服务
                7、跳转到首页
                :param request:
                :return:
                '''
        mobile=req.POST.get('mobile')
        password=req.POST.get('password')
        remembr=req.POST.get('remembr')


        if not all([mobile,password]):
            return render(req,"login.html",{'msg':'参数不齐全'})

        if not re.match('^1[3-9]\d{9}$',mobile):
            return render(req,"login.html",{'msg':'手机号码格式不正确'})

        if not re.match('^[a-z0-9A-Z]{8,20}$',password):
            return render(req, "login.html", {'msg':'密码格式不正确'})

        #使用django自带的用户认证代码，将会返回一个user对象，如果账号密码正确，那么就返回对象，否则返回None
        return_user = authenticate(mobile=mobile,password=password)
        # if return_user is None:
        #     return render(req, "login.html", {'msg':'账号或密码错误'})

        # print(return_user)
        login(req,return_user)

        # 6、设置cookie信息，为首页显示服务
        # 根据匿名登录跳转参数next，跳转到指定页面
        next_page = req.GET.get('next')
        if next_page:
            resp = redirect(next_page)
        else:
            resp = redirect(reverse('home:index'))

        if remembr!='on':
            req.session.set_expiry(0)
            resp.set_cookie('is_login',True)
            u=json.dumps(return_user.username)
            resp.set_cookie('login_name',u)
        else:
            req.session.set_expiry(None)
            resp.set_cookie('is_login', True,max_age=14 * 24 * 3600)
            u = json.dumps(return_user.username)
            resp.set_cookie('login_name', u,max_age=14 * 24 * 3600)
        return resp


#退出视图
class LogoutView(View):
    def get(self, req):
        '''
        实现思路：
        1、清楚session数据
        2、删除cookie数据
        3、跳转到首页
        :param request:
        :return:
        '''
        # 实现思路：
        # 1、清楚session数据
        logout(req)
        # 2、删除cookie数据
        resp = redirect(reverse('home:index'))
        resp.delete_cookie('is_login')
        resp.delete_cookie('login_name')
        # 3、跳转到首页
        return resp


#忘记密码
class ForgetPasswordView(View):
    def get(self, request):
        return render(request, 'forget_password.html')

    def post(self, request):
        '''
        实现思路：
        1、接收数据
        2、验证数据
        2-1、判断参数是否齐全
        2-2、手机号是否符合规则
        2-3、判断密码是否符合规则
        2-4、判断确认密码是否一致
        2-5、判断短信验证码是否正确
        3、根据手机号码进行用户信息的查询
        4、如果手机号查询出用户信息则进行用户密码的修改
        5、如果手机号没有查询出用户信息，则进行新用户的创建
        6、进行页面跳转，跳转到登录页面
        7、返回响应
        :param request:
        :return:
        '''
        # 1、接收数据
        mobile = request.POST.get('mobile')
        password = request.POST.get('password')
        password2 = request.POST.get('password2')
        sms_code = request.POST.get('sms_code')
        # 2、验证数据
        # 2-1、判断参数是否齐全
        if not all([mobile, password, password2, sms_code]):
            return HttpResponseBadRequest('缺少必要的参数')
        # 2-2、手机号是否符合规则
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return HttpResponseBadRequest('手机格式不正确')
        # 2-3、判断密码是否符合规则
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return HttpResponseBadRequest('密码格式不正确')
        # 2-4、判断确认密码是否一致
        if password != password2:
            return HttpResponseBadRequest('两次密码输入不一致')
        # 2-5、判断短信验证码是否正确
        redis_conn = get_redis_connection('default')
        redis_sms_code = redis_conn.get('sms:%s' % mobile)
        if redis_sms_code is None:
            return HttpResponseBadRequest('短信验证码过期')
        try:
            if redis_sms_code.decode() != sms_code:
                return HttpResponseBadRequest('验证码错误')
        except Exception as e:
            logger.error(e)
            return HttpResponseBadRequest('验证码错误')
        # 3、根据手机号码进行用户信息的查询
        return_user = User.objects.filter(mobile=mobile).first()
        # 4、如果手机号查询出用户信息则进行用户密码的修改
        # 5、如果手机号没有查询出用户信息，则进行新用户的创建
        if return_user is None:
            try:
                User.objects.create_user(username=mobile, mobile=mobile, password=password)
            except Exception as e:
                logger.error(e)
                return HttpResponseBadRequest('注册失败')

        else:
            try:
                # 调用系统user对象的set_password()进行修改密码，该方法会对密码进行加密
                return_user.set_password(password)
                return_user.save()
            except Exception as e:
                logger.error(e)
                return HttpResponseBadRequest('修改密码失败')
        # 6、进行页面跳转，跳转到登录页面
        resp = redirect(reverse('users:login'))
        # 7、返回响应
        return resp


#用户中心展示
class UserCenterView(LoginRequiredMixin,View):
    def get(self, request):
        userinfo = request.user
        context = {
            'username': userinfo.username,
            'mobile': userinfo.mobile,
            'avatar': userinfo.avatar.url if userinfo.avatar else None,
            'user_desc': userinfo.user_desc
        }
        return render(request, 'usercenter.html', context=context)

    def post(self, request):
        '''
        实现思路：
        1、接收用户参数
        2、将用户参数更新到数据库
        3、更新cookie中的username
        4、刷新当前页面（重定向操作）
        5、返回相应
        :param request:
        :return:
        '''

        # 获取已经登录用户的信息
        userinfo = request.user
        # 1、接收用户参数
        # 获取用户提交的用户名，如果没有就将已登录的用户名赋值
        username = request.POST.get('username', userinfo.username)
        # 获取用户提交的介绍，如果没有就将已登录的介绍赋值
        user_desc = request.POST.get('desc', userinfo.user_desc)
        # 获取用户头像(如果没有图片保存地址，则会默认保存到项目的根目录下。否则需要在settting中进行配置地址
        avatar = request.FILES.get('avatar')
        # 2、将用户参数更新到数据库
        try:
            userinfo.username = username
            userinfo.user_desc = user_desc
            if avatar:
                userinfo.avatar = avatar
            userinfo.save()
        except Exception as e:
            logger.error(e)
            return HttpResponseBadRequest('修改用户信息失败')
        # 3、更新cookie中的username
        # 4、刷新当前页面（重定向操作）
        resp = redirect(reverse('users:usercenter'))
        u=json.dumps(username)
        resp.set_cookie('login_name', u)
        # 5、返回相应
        return resp


# 写博客视图
class WriteBlogView(View):
    def get(self, requset):
        centxt =ArticleCategory.objects.all()
        return render(requset, 'writeblog.html',context={'list':centxt})

    def post(self, request):
        '''
        实现思路：
        1、接收数据
        2、验证数据
        3、数据入库
        4、跳转到指定页面
        :param request:
        :return:
        '''
        # 1、接收数据
        avatar = request.FILES.get('avatar')
        title = request.POST.get('title')
        category_id = request.POST.get('category')
        tags = request.POST.get('tags')
        sumary = request.POST.get('sumary')
        content = request.POST.get('content')

        user = request.user
        # 2、验证数据
        # 2-1、参数齐全验证
        if not all([avatar, title, category_id,sumary, content]):
            return HttpResponseBadRequest('参数不齐全')
        # 2-2、判断分类id
        try:
            category = ArticleCategory.objects.filter(pk=category_id).first()
        except ArticleCategory.DoesNotExist:
            return HttpResponseBadRequest('没有该分类信息')
        # 3、数据入库
        try:
            Article.objects.create(
                author=user,
                title=title,
                avatar=avatar,
                category=category,
                tags=tags,
                sumary=sumary,
                content=content
            )
        except Exception as e:
            logger.error(e)
            return HttpResponseBadRequest('发布失败，请稍后重试')
        # 4、跳转到指定页面
        return redirect(reverse('home:index'))


#查询分类数据并展示
class IndexView(View):
    def get(self, request):
        # 1、获取所有分类信息数据
        categories = ArticleCategory.objects.all()
        # 2、接收用户点击的分类id
        cat_id = request.GET.get('cat_id', 1)
        # 3、根据分类id进行分类的查询
        try:
            category = ArticleCategory.objects.get(id=cat_id)
        except ArticleCategory.DoesNotExist:
            return HttpResponseBadRequest('此分类信息不存在')
        # 4、获取分页参数
        page_index = request.GET.get('page_index', 1)  # 页码
        page_size = request.GET.get('page_size', 2)  # 页容量
        # 5、根据分类信息查询该分类下的所有文章数据
        articles = Article.objects.filter(category=category)
        # 6、创建分页器
        from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger  # 导入django分页插件
        pages = Paginator(articles, page_size)  # 对查询到的数据对象articles进行分页，设置超过指定页容量就分页

        try:
            list = pages.page(page_index)  # 获取当前页面的记录
        except PageNotAnInteger:
            list = pages.page(1)  # 如果用户输入的页面不是整数时，显示第1页的内容
        except EmptyPage:
            list = pages.page(pages.num_pages)  # 如果用户输入的页数不在系统的页码列表中时,显示最后一页的内容
        # 4、组织数据传递给模板
        context = {
            'categories': categories,
            'category': category,
            'articles': list,
            'cat_id':cat_id
        }
        return render(request, 'index.html', context=context)
